package com.medic.util;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * json数据转换帮助类
 * @author Mr.zhang
 *
 */
public class JsonUtil {

	/**
	 * 自定义时间格式
	 */
	private static SimpleDateFormat format;
	/**
	 * ObjectMapper对象
	 */
	private static ObjectMapper objectMapper;

	/**
	 * 初始化
	 */
	static {
		format = new SimpleDateFormat("yyyy-MM-dd hh-mm-ss");
		objectMapper = new ObjectMapper();
		objectMapper.setDateFormat(format);
	}

	/**
	 * 将obj对象转化成json
	 * 
	 * @param obj
	 *            对象
	 * @return 返回json
	 */
	public static String getJson(Object obj) {
	
		
		String json = null;
		try {
			json = objectMapper.writeValueAsString(obj);
		} catch (Exception e) {
			json = null;
			e.printStackTrace();
		}
		return json;
	}

	/**
	 * 通过response的printwriter写json到网络
	 * 
	 * @param response
	 * @param obj
	 *            需要写入的对象
	 */
	public static void writeJsonByRes(HttpServletResponse response, Object obj) {
		String json = null;
		PrintWriter out = null;
		try {
			out = response.getWriter();
			json = objectMapper.writeValueAsString(obj);
			out.write(json);
			out.flush();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (out != null) {
				out.close();
			}
		}
	}

	/**
	 * 通过jackson自带的方法写json
	 * 
	 * @param response
	 * @param obj
	 */
	public static void writeJsonByJackson(HttpServletResponse response, Object obj) {
		ServletOutputStream out = null;
		JsonGenerator jsonGener = null;
		try {
			// 获取输出流
			out = response.getOutputStream();
			// 获取jsonGennerator
			jsonGener = objectMapper.getFactory().createGenerator(out, JsonEncoding.UTF8);
			// 写入
			jsonGener.writeObject(obj);
			jsonGener.flush();

		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (out != null) {
					out.close();
				}
				if (jsonGener != null) {
					jsonGener.close();
				}
			} catch (IOException ie) {
				ie.printStackTrace();
			}
		}
	}

	/**
	 * 将json转化成对应的类对象
	 * 
	 * @param json
	 *            json字符串
	 * @param clazz
	 *            要转化成的类型
	 * @return 返回的对象
	 */
	public static Object getObject(String json, Class<?> clazz) {
		Object obj = null;
		try {
			obj = objectMapper.readValue(json, clazz);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return obj;
	}
	
	/**
	 * 根据key 获取value 字符串，如果是数组，则会用，分割
	 * @param json 
	 * @param key 
	 * @return value
	 */
	public static String getValue(String json,String key){
		String value = "";
		JsonParser jsonParser;
		try{
			jsonParser = objectMapper.getFactory().createParser(json);
			while(jsonParser.nextToken() != null){
				if(jsonParser.getText().equals(key) && jsonParser.nextToken() != null && jsonParser.getCurrentToken() != JsonToken.START_OBJECT){
					if(jsonParser.getCurrentToken() == JsonToken.START_ARRAY){
						while(jsonParser.nextToken() != JsonToken.END_ARRAY){
							value = value + jsonParser.getText() + ",";
						}
					}else {
						value = jsonParser.getText();
					}
					break;
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}
		return value;
	}

	/**
	 * 获取List<object> 但是object对象中只包含基本数据
	 * 
	 * @param json
	 *            json数据
	 * @param clazz
	 *            类
	 * @return 返回list<object>
	 */
	@SuppressWarnings("unchecked")
	public static List<Object> getList(String json, Class<?> clazz) {
		List<Object> list = null;
		JavaType javaType = null;
		try {
			javaType = objectMapper.getTypeFactory().constructCollectionType(ArrayList.class, clazz);
			list = objectMapper.readValue(json, javaType);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return list;
	}

	/**
	 * 获取对象中含有 list的对象 （只能获取对象中包含 list map 类型的）
	 * @param json json 数据
	 * @param clazz 本对象的class类型
	 * @return 对象
	 */
	public static Object getSelfObject(String json, Class<?> clazz) {
		Object obj = null;
		try {
			//根据clazz反射实例化一个对象
			obj = clazz.newInstance();
			//将json转换成map
			Map<String, Object> map = (Map<String, Object>) objectMapper.readValue(json, Map.class);
			//获取clazz中所有的字段
			Field[] fields = clazz.getDeclaredFields();
			Class<?> cls = null;
			Method method = null;
			//对每一个字段进行遍历
			for (Field field : fields) {
				//获取字段的类型
				cls = field.getType();
				//如果字段是list集合
				if (cls != null
						&& (cls.equals(List.class) || cls.equals(ArrayList.class) || cls.equals(LinkedList.class))) {
					//获取对应字段的set方法
					method = clazz.getMethod(StringUtil.getMethodName(field.getName()), cls);
					//获取list集合中存放的对象类型 clz 就是list中对象的class类型
					ParameterizedType pt = (ParameterizedType) field.getGenericType() ;
					Class<?> clz = (Class<?>) pt.getActualTypeArguments()[0];
					//执行set方法 getSelfList 是根据json 获取list集合的方法
					method.invoke(obj,
							getSelfList(getJson(map.get(field.getName())), clz));
					//如果是字段是map类型
				} else if (cls != null
						&& (cls.equals(Map.class) || cls.equals(HashMap.class) || cls.equals(LinkedHashMap.class))) {
					//获取set 方法 在直接调用 将map set到字段中
					method = clazz.getMethod(StringUtil.getMethodName(field.getName()), cls);
					method.invoke(obj, map.get(field.getName()));
					//其他类型（这个方法不支持其他特殊集合类型）剩下的都是基本类型的转换
				} else {
					method = clazz.getMethod(StringUtil.getMethodName(field.getName()), cls);
					//如果还有map 但是对应字段是String 那么默认该字段存放的是一个json格式的数据
					if (map.get(field.getName()) instanceof Map && cls.equals(String.class)) {
						method.invoke(obj, getJson(map.get(field.getName())));
					}else if(!(map.get(field.getName()) instanceof Map)){
						//普通属性进行转换
						method.invoke(obj, map.get(field.getName()));
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return obj;
	}

	/**
	 * 获取包含嵌套的list （本身是list集合，然后其中又嵌套list或者map）
	 * 
	 * @param json
	 *            json
	 * @param clazz
	 *            list集合中所包含对象的class类型
	 * @return 返回list
	 */
	public static List<Object> getSelfList(String json, Class<?> clazz) {
		List<Object> resList = new ArrayList<Object>();
		try {
			//将json转换格式，以便操作
			List<Map<String, Object>> list = objectMapper.readValue(json, ArrayList.class);
			Field[] fields = clazz.getDeclaredFields();
			Class<?> cls = null;
			Method method = null;
			Object obj = null;
			for (Map<String, Object> map : list) {
				//实例化一个对象，以便插入值，每一次新的循环都需要实例化
				obj = clazz.newInstance();
				//遍历所有字段
				for (Field field : fields) {
					cls = field.getType();
					//以下注释与getSelfObject方法中的类似
					if (cls != null && (cls.equals(List.class) || cls.equals(ArrayList.class)
							|| cls.equals(LinkedList.class))) {
						method = clazz.getMethod(StringUtil.getMethodName(field.getName()), cls);
						ParameterizedType pt = (ParameterizedType) field.getGenericType() ;
						Class<?> clz = (Class<?>) pt.getActualTypeArguments()[0];
						method.invoke(obj,
								getSelfList(getJson(map.get(field.getName())), clz));
					} else if (cls != null && (cls.equals(Map.class) || cls.equals(HashMap.class)
							|| cls.equals(LinkedHashMap.class))) {
						method = clazz.getMethod(StringUtil.getMethodName(field.getName()), cls);
						method.invoke(obj, map.get(field.getName()));
					} else {
						method = clazz.getMethod(StringUtil.getMethodName(field.getName()), cls);
						if (map.get(field.getName()) instanceof Map && cls.equals(String.class)) {
							method.invoke(obj, getJson(map.get(field.getName())));
						}else if(!(map.get(field.getName()) instanceof Map)){
							method.invoke(obj, map.get(field.getName()));
						}
					}
				}
				resList.add(obj);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return resList;
	}
	
	/**
	 * 根据key值 获取 对应的字符串或者字符串数组
	 * @param key 
	 * @param json 需要进行提取的json
	 * @return 字符串list
	 */
	public static List<String> getToken(String key,String json){
		JsonParser jsonParser;
		List<String> strs = new ArrayList<String>();
		try{
			jsonParser = objectMapper.getFactory().createParser(json);
			while(jsonParser.nextToken() != null){
				if(jsonParser.getText().equals(key) && jsonParser.nextToken() != JsonToken.START_OBJECT){
					if(jsonParser.getCurrentToken() == JsonToken.START_ARRAY){
						while(jsonParser.nextToken() != JsonToken.END_ARRAY){
							strs.add(jsonParser.getText());
						}
					}else {
						strs.add(jsonParser.getText());
					}
					break;
				}
			}
		}catch (Exception e){
			e.printStackTrace();
		}
		return strs;
	}
}
